/*
 * kfile example
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mm.h>

#define LOG_PATH "./log.txt"
#define BUF_SIZE 256


//add timestamp to msg
static void format_msg(char *buf, int size, char *msg)
{
	time64_t now;
	struct tm time_info;

	now = ktime_get_real_seconds();
	time64_to_tm(now, 3600*8, &time_info); //东8区

	snprintf(buf, size-1, "[%ld-%02d-%02d %02d:%02d:%02d] %s\n",
		time_info.tm_year + 1900, time_info.tm_mon + 1, time_info.tm_mday,
		time_info.tm_hour, time_info.tm_min, time_info.tm_sec, msg);
}

static int __init kfile_init(void)
{
	struct file *logfile;

	char buf[BUF_SIZE] = {0};
	int ret = 0;

	pr_info("%s\n", __func__);

	//切换地址空间, 但5.10已经不再使用该代码, 参考 https://lwn.net/Articles/832121/
	//mm_segment_t old_fs;
	// old_fs = get_fs();
	// set_fs(KERNEL_DS);
	// ... //file operation
	// set_fs(old_fs);

	logfile = filp_open(LOG_PATH, O_RDWR | O_APPEND | O_CREAT, 0664);
	if (IS_ERR(logfile)) {
		pr_err("filp_open %s failed\n", LOG_PATH);
		return -EFAULT;
	}

	// snprintf(buf, BUF_SIZE, "write from kernel!\n");
	format_msg(buf, BUF_SIZE, "write from kernel!");

	ret = kernel_write(logfile, buf, strlen(buf), &logfile->f_pos);
	if (ret < 0) {
		pr_err("kernel_write %s failed\n", buf);
		ret = -EFAULT;
		goto exit;
	}

exit:
	filp_close(logfile, NULL);

	return 0;
}

static void __exit kfile_exit(void)
{
	pr_info("%s...\n", __func__);
}

module_init(kfile_init);
module_exit(kfile_exit);
MODULE_LICENSE("GPL");
